package com.globallogic.javatrainings.sergiiivanov.model;

import java.io.Serializable;

import com.globallogic.javatrainings.sergiiivanov.resources.ErrorCodes;

/**
 * Extends {@link Person}<br>
 * Represent student in the application<br>
 * Keeps information about student and links to courses and scores
 * 
 * @author Sergey
 * @see #Student(String, String, String)
 */
public class Student extends Person implements Serializable {

    private static final long serialVersionUID = 1L;
    private MyArray<ScoreRecord> scoreTable;
    private MyArray<Course> courses;

    /**
     * Quick constructor
     * 
     * @param name
     *            - String, required, (inherited from {@link Person}).
     *            Represents name of the student. Usually in format
     *            "FirstName LastName"
     * @param mobile
     *            - String, nulls auto-converted into "" , (inherited from
     *            {@link Person}). Represents phone or mobile number of the
     *            student
     * @param email
     *            - String, nulls auto-converted into "", (inherited from
     *            {@link Person}). Represents email address of the student\' s
     *            personal mailbox
     * @throws UniversityWarning
     *             - (inherited from {@link Person}), thrown on empty
     *             <b>name</b>
     */
    public Student(String name, String mobile, String email) throws UniversityWarning {
        super(name, mobile, email);
        scoreTable = new MyArray<ScoreRecord>(new ScoreRecord[0]);
        courses = new MyArray<Course>();
    }

    /**
     * Links student to course
     * 
     * @param c
     *            {@link Course}
     */
    protected void addCourse(Course c) {
        if (courses.indexOf(c) < 0) {
            courses.add(c);
        }
    }

    /**
     * Removes course link
     * 
     * @param c
     *            {@link Course}
     */
    protected void removeCourse(Course c) {
        courses.remove(c);
    }

    /**
     * Default constructor. Used in StudentsManager.addStudent()
     */
    public Student() {
        super();
        scoreTable = new MyArray<ScoreRecord>(new ScoreRecord[0]);
        courses = new MyArray<Course>();
    }

    /**
     * Adds {@link ScoreRecord} into inner collection. This collections
     * represents education progress of the individual.
     * 
     * @param lecture
     *            see {@link ScoreRecord}
     * @param score
     *            see {@link ScoreRecord}
     * @param scoreReason
     *            see {@link ScoreRecord}
     * @throws UniversityWarning
     *             student is not enrolled to course or see
     *             ScoreRecord(Lecture, int, String)
     */
    public final void addScore(final Lecture lecture, int score, String scoreReason) throws UniversityWarning {

        if (lecture != null && lecture.getCourse() != null) {
            if (lecture.getCourse() != null
                    && lecture.getCourse().isStudentEnrolled(this)) {
                
                ScoreRecord s = new ScoreRecord(this, lecture, score, scoreReason);
                scoreTable.add(s);

            } else {
                throw new UniversityWarning(ErrorCodes.STUDENT_NOT_ENROLLED_TO + lecture.getCourse().getName());
            }
        } else {
            throw new UniversityWarning(ErrorCodes.SCORE_COURSE_NULL);
        }
    }

    /**
     * Calls {@link ScoresProcessor} to generate average scores report
     * 
     * @return print ready average scores report table as String[][]
     * @throws UniversityWarning
     *             should not return until MyMap is not broken
     * @throws UniversityFailure
     *             application crash
     */
    public String[][] getAverageScore() throws UniversityFailure, UniversityWarning {
        ScoresProcessor sp = new ScoresProcessor();
        sp.setScoresCollection(scoreTable);
        return sp.getAveragesDiscipline();
    }

    /**
     * Returns copy of course links
     * 
     * @return {@link MyArray} of {@link Course}
     */
    public MyArray<Course> getCoursesList() {
        return courses.copy();
    }

    /**
     * Uses {@link ScoresProcessor} to generate scores report
     * 
     * @return score table as String[][]
     * 
     */
    public String[][] getScores() {
        ScoresProcessor sp = new ScoresProcessor();
        sp.setScoresCollection(scoreTable);
        return sp.getTable();
    }

    /**
     * Removes all links to the student. Used before removing the student.<br>
     * Disenroll student from all courses and removes all student score records
     * 
     * @throws UniversityFailure
     *             fatal failure from {@link Course#disenrollStudent(Student)}
     */
    void removeLinks() throws UniversityFailure {
        for (Course c : courses.copy()) {
            try {
                c.disenrollStudent(this);
            } catch (UniversityWarning e) {}
        }
        courses.clear();

        for (ScoreRecord sr : scoreTable.copy()) {
            if (sr != null)
                sr.removeLinks();
        }
        scoreTable.clear();
    }
}
